﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MacomberMapSystem.Common.Serialization;
using System.Xml;
using MacomberMapSystem.Common.Database;
using MacomberMapSystem.Common.CIM;
using System.IO;

namespace MacomberMapSystem.Common.Processing
{
    /// <summary>
    /// This class produces a list of all of the RASs and their assocaited breaker-to-breakers
    /// </summary>
    public class CIM_RASListGenerator : CIM_Processor
    {
        /// <summary>
        /// Report our process name
        /// </summary>
        public override string ProcessName
        {
            get { return "RAS List Generator"; }
        }


        /// <summary>
        /// Initialize our named list generator
        /// </summary>
        /// <param name="xElem"></param>
        /// <param name="NamedParameters"></param>
        /// <param name="Repository"></param>
        public CIM_RASListGenerator(XmlElement xElem, Dictionary<String, Object> NamedParameters, MM_Repository Repository)
            : base(xElem, NamedParameters, Repository)
        {
        }


        /// <summary>
        /// Write out our list of RASs
        /// </summary>
        /// <param name="DbConn"></param>
        /// <returns></returns>
        public override CIM_Processor.enumProcessState InitiateProcess(Database.MM_Database_Connector DbConn)
        {
            MM_Database_Model Model = NamedParameters["Model"] as MM_Database_Model;
            IncludeAttachments = true;
            this.TargetFolder = Model.ModelFullPath;
            this.TargetFileName = Model.NameWithoutExtension + "-RemedialActionSchemes.xml";
            CIM_Element[] RASs = Model.ElementsOfType("etx:RemedialActionScheme");
            Total = RASs.Length;
            int SPSCount=0, RAPCount = 0;

            List<String> OutLines = new List<string>();
            using (XmlTextWriter xW = new XmlTextWriter(Path.Combine(TargetFolder, TargetFileName ), new UTF8Encoding(false)))
            {
                xW.Formatting = System.Xml.Formatting.Indented;
                xW.WriteStartDocument();
                xW.WriteStartElement("RemedialActionSchemes");
                for (int a = 0; a < RASs.Length; a++)
                    if (RASs[a].SPSorRAPInputs.Length > 0)
                    {
                        Current = a;
                        CIM_Element RAS = RASs[a];
                        bool SPS = XmlConvert.ToBoolean(RAS.Attributes["etx:RemedialActionScheme.isRAS"]);
                        bool RAP = XmlConvert.ToBoolean(RAS.Attributes["etx:RemedialActionScheme.isRAP"]);
   
                        if (SPS)
                            SPSCount++;
                        if (RAP)
                            RAPCount++;
                        
                       
                            xW.WriteStartElement("RemedialActionScheme");
                            xW.WriteAttributeString("Name", RAS.Name);
                            xW.WriteAttributeString("IsRAS", RAS.Attributes["etx:RemedialActionScheme.isRAS"]);
                            xW.WriteAttributeString("IsRAP", RAS.Attributes["etx:RemedialActionScheme.isRAP"]);
                            

                        


                     

                        CIM_Element AlreadyCtg = RAS.ParseSingle("cim:Contingency",null);
                        int HeaderLine = OutLines.Count;
                        OutLines.Add((SPS ? "SPS" : "") + (RAP ? "RAP" : "") + " " + RAS.Name + " (" + RAS.SPSorRAPInputs.Length.ToString() + ")" + (AlreadyCtg == null ? "" : " => " + AlreadyCtg.Name));

                        //Now, produce our list of inputs
                        xW.WriteStartElement("Inputs");
                        Dictionary<CIM_Trace, int> Traces = new Dictionary<CIM_Trace, int>();
                        foreach (CIM_Element Input in RAS.SPSorRAPInputs)
                        {
                            WriteElement(xW, Input);
                            foreach (CIM_Trace Trace in Input.AssociatedTraces)
                                if (Traces.ContainsKey(Trace))
                                    Traces[Trace]++;
                                else
                                    Traces.Add(Trace, 1);
                        }
                        xW.WriteEndElement();

                        xW.WriteStartElement("Outputs");
                        foreach (CIM_Element Output in RAS.SPSorRAPOutputs)
                            WriteElement(xW, Output);
                        xW.WriteEndElement();

                        xW.WriteStartElement("Contingencies");

                        //Now, calculate our max
                        int Max = 0;
                        foreach (int i in Traces.Values)
                            Max = Math.Max(Max, i);

                        for (int CurLevel = Max; CurLevel > 0; CurLevel--)
                        {
                            List<String> OutTraces = new List<string>();
                            foreach (KeyValuePair<CIM_Trace, int> Trace in Traces)
                                if (Trace.Value == CurLevel)
                                {
                                    if (Trace.Value == RAS.SPSorRAPInputs.Length && (Trace.Key.Name.StartsWith("S") || Trace.Key.Name.StartsWith("X") || Trace.Key.Name.StartsWith("U")))
                                        OutLines[HeaderLine] += " Best guess: " + Trace.Key.Name;
                                    WriteElement(xW, Trace.Key, Trace.Value);
                                    OutTraces.Add("\t" + Trace.Key.Name + ": " + Trace.Value.ToString());
                                }
                            OutTraces.Sort();
                            OutLines.AddRange(OutTraces);
                        }
                        xW.WriteEndElement();
                        xW.WriteEndElement();
                    }
                xW.WriteEndElement();
                xW.WriteEndDocument();
            }

            ProcessLog.AppendLine("Total RAS elements: " + Total.ToString());
            ProcessLog.AppendLine("Total SPS elements: " + SPSCount.ToString());
            ProcessLog.AppendLine("Total RAP elements: " + RAPCount.ToString());
            foreach (String str in OutLines)
                ProcessLog.AppendLine(str);

            return enumProcessState.Completed;
        }

        /// <summary>
        /// Write out our element
        /// </summary>
        /// <param name="xW"></param>
        /// <param name="Elem"></param>
        private void WriteElement(XmlTextWriter xW, CIM_Element Elem)
        {
            WriteElementXml(xW, Elem);
            xW.WriteEndElement();
        }

        /// <summary>
        /// Write an element w/ a count
        /// </summary>
        /// <param name="xW"></param>
        /// <param name="Elem"></param>
        /// <param name="InputCount"></param>
        private void WriteElement(XmlTextWriter xW, CIM_Element Elem, int InputCount)
        {
            WriteElementXml(xW, Elem);
            xW.WriteAttributeString("InputCount", InputCount.ToString());
            xW.WriteEndElement();
        }

        /// <summary>
        /// Write out the XML for our element
        /// </summary>
        /// <param name="xW"></param>
        /// <param name="Elem"></param>
        private void WriteElementXml(XmlTextWriter xW, CIM_Element Elem)
        {
            xW.WriteStartElement(Elem.ElemType);
            xW.WriteAttributeString("rdfID", Elem.rdfID.ToString());
            if (!String.IsNullOrEmpty(Elem.TEID))
                xW.WriteAttributeString("TEID", Elem.TEID);
            xW.WriteAttributeString("Name", Elem.LineName);

            if (Elem.TypeName == "cim:TransformerWinding")
                xW.WriteAttributeString("Transformer", Elem.ParseSingle("cim:PowerTransformer", null).Name);


            if (Elem.VoltageLevel != null)
                xW.WriteAttributeString("Voltage", Elem.VoltageLevel.Name);

            if (Elem.Substation != null)
                xW.WriteAttributeString("Substation", Elem.Substation.Name);

            if (Elem.TypeName == "cim:ACLineSegment")
                xW.WriteAttributeString("Substations", Elem.ACSegmentStations[0].Name + " to " + Elem.ACSegmentStations[1].Name);


            List<string> Ctgs = new List<string>();
            foreach (CIM_Trace Trace in Elem.AssociatedTraces)
                if (!Ctgs.Contains(Trace.Name))
                    Ctgs.Add(Trace.Name);
            if (Ctgs.Count > 0)
                xW.WriteAttributeString("Traces", String.Join(",", Ctgs.ToArray()));


            //  xW.WriteEndElement();
        }
    }
}
